package com.xiguaji.tiktok.task.blogger.event;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import com.gugee.tiktok.common.model.dal.blogger.BloggerMainRepository;
import com.gugee.tiktok.common.model.dal.blogger.TAwemeRecordRepository;
import com.gugee.tiktok.common.model.dal.blogger.TBloggerRecordRepository;
import com.gugee.tiktok.common.model.dal.blogger.TBloggerRepository;
import com.gugee.tiktok.common.model.dto.SlimBloggerDto;
import com.gugee.tiktok.common.model.mysql.*;
import com.xiguaji.boot.eventbus.Event;
import com.xiguaji.boot.eventbus.EventBusTemplate;
import com.xiguaji.boot.eventbus.IEventListener;
import com.xiguaji.tiktok.task.aweme.AwemeService;
import com.xiguaji.tiktok.task.blogger.client.AwemeClient;
import com.xiguaji.tiktok.task.core.ScheduleTemplate;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
public class MonitorBloggerMainRecordEventListener implements IEventListener<MonitorBloggerMainRecordEventListener.MonitorBloggerMainRecordEvent> {

    @Autowired
    AwemeService awemeService;

    @Autowired
    TBloggerRepository tBloggerRepository;

    @Autowired
    TBloggerRecordRepository tBloggerRecordRepository;

    @Autowired
    TAwemeRecordRepository tAwemeRecordRepository;

    @Autowired
    BloggerMainRepository bloggerMainRepository;

    @Autowired
    @Lazy
    EventBusTemplate eventBusTemplate;

    @Autowired
    ScheduleTemplate scheduleTemplate;

    @Autowired
    AwemeClient awemeClient;

    private ThreadPoolExecutor monitorBloggerPool;
    private int queueSize=30000;
    private int corePollSize=50;

    @PostConstruct
    public void init() {
        monitorBloggerPool = scheduleTemplate.getCustomThreadPool("MonitorBloggerMain-worker", corePollSize, corePollSize, 0, queueSize, TimeUnit.MINUTES);
    }


    @Override
    @Subscribe
    @AllowConcurrentEvents
    public void handle(MonitorBloggerMainRecordEvent event) {
        Collection<Future<?>> futures = new LinkedList<Future<?>>();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND,0);
        event.slimBloggers.forEach( slimBloggerDto -> futures.add(monitorBloggerPool.submit(()-> recordBlogger(event,slimBloggerDto.getUid(),calendar))));

        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
                XxlJobLogger.log(e);
            } catch (ExecutionException e) {
                e.printStackTrace();
                XxlJobLogger.log(e);
            }
        }

    }


    private void recordBlogger(MonitorBloggerMainRecordEvent event,long uid,Calendar calendar){
        Optional<BloggerMain> bloggerMainOptional = bloggerMainRepository.findByoUid(uid);
        Calendar beforeCalendar = ObjectUtil.cloneByStream(calendar);
        beforeCalendar.add(Calendar.HOUR_OF_DAY,-1);

        if(bloggerMainOptional.isPresent()){

            BloggerMain bloggerMain = bloggerMainOptional.get();
            val bloggerRecordOptional = tBloggerRecordRepository.findByUidAndRecordDate(uid, calendar.getTimeInMillis() / 1000);

            TBloggerRecord tBloggerRecord;
            if(bloggerRecordOptional.isPresent()){
                tBloggerRecord = bloggerRecordOptional.get();
            }else {
                tBloggerRecord = new TBloggerRecord();
                tBloggerRecord.setCreateBy(event.getSource());
                tBloggerRecord.setRecordDate(calendar.getTimeInMillis()/1000);
            }


            // 获取90天的数据(今天的数据)
            val curBloggerAwemeExtendDto = awemeClient.getBloggerRecordForZeroTimeAwemeExtendDto(bloggerMain.getOUid(),30);
            tBloggerRecord.setUid(bloggerMain.getOUid());
            tBloggerRecord.setFollowerCount((long)bloggerMain.getOFollowerCount());
            tBloggerRecord.setFollowerGrowth(0l);
            tBloggerRecord.setLikeCount(bloggerMain.getOTotalFavorited());
            tBloggerRecord.setLikeGrowth(0l);
            tBloggerRecord.setPostsCount((long)bloggerMain.getOAwemeCount());
            tBloggerRecord.setPostsGrowth(0l);
            tBloggerRecord.setReviewCount(curBloggerAwemeExtendDto.getReviewsCount());
            tBloggerRecord.setReviewGrowth(0l);
            tBloggerRecord.setShareCount(curBloggerAwemeExtendDto.getShareCount());
            tBloggerRecord.setShareGrowth(0l);
            tBloggerRecord.setViewCount(curBloggerAwemeExtendDto.getViewsCount());
            tBloggerRecord.setViewGrowth(0l);
            tBloggerRecord.setCycle(0);
            tBloggerRecord.setUpdateBy(event.getSource());
            Optional<TBloggerRecord> tBloggerRecordOptional = tBloggerRecordRepository.findByUidAndRecordDate(uid,beforeCalendar.getTimeInMillis()/1000);

            if(tBloggerRecordOptional.isPresent()){
                TBloggerRecord beforeBloggerRecord = tBloggerRecordOptional.get();
                tBloggerRecord.setFollowerGrowth(tBloggerRecord.getFollowerCount() - beforeBloggerRecord.getFollowerCount());
                tBloggerRecord.setPostsGrowth(bloggerMain.getOAwemeCount() - beforeBloggerRecord.getPostsCount());
                tBloggerRecord.setLikeGrowth(tBloggerRecord.getLikeCount() - beforeBloggerRecord.getLikeCount());

                // 新一天的时刻
                if(calendar.get(Calendar.HOUR_OF_DAY) == 0){
                    // 获取91天的数据(今天的数据)
                    val curBloggerRecordAwemeExtendDto = awemeClient.getBloggerRecordForZeroTimeAwemeExtendDto(bloggerMain.getOUid(),31);
                    tBloggerRecord.setReviewGrowth(curBloggerRecordAwemeExtendDto.getReviewsCount() - beforeBloggerRecord.getReviewCount());
                    tBloggerRecord.setShareGrowth(curBloggerRecordAwemeExtendDto.getShareCount() - beforeBloggerRecord.getShareCount());
                    tBloggerRecord.setViewGrowth(curBloggerRecordAwemeExtendDto.getViewsCount() - beforeBloggerRecord.getViewCount());
                }else{
                    tBloggerRecord.setReviewGrowth(tBloggerRecord.getReviewCount() - beforeBloggerRecord.getReviewCount());
                    tBloggerRecord.setShareGrowth(tBloggerRecord.getShareCount() - beforeBloggerRecord.getShareCount());
                    tBloggerRecord.setViewGrowth(tBloggerRecord.getViewCount() - beforeBloggerRecord.getViewCount());
                }
            }



            tBloggerRecordRepository.save(tBloggerRecord);

            // 更新TBlogger数据
            Optional<BloggerMain> optionalBloggerMain = bloggerMainRepository.findByoUid(uid);

            if(optionalBloggerMain.isPresent()){
                List<TBlogger> tBloggerList = tBloggerRepository.findByUid(uid);
                BloggerMain blogger = optionalBloggerMain.get();
                for (TBlogger tBlogger : tBloggerList) {
                    tBlogger.setAvatar(blogger.getOAvatar168());
                    tBlogger.setNickname(blogger.getONickname());
                    tBlogger.setRegion(blogger.getORegion());
                    tBlogger.setUniqueId(blogger.getOUniqueId());
                    tBloggerRepository.save(tBlogger);
                }
            }
        }

        recordAweme(event,uid,calendar);
    }

    private void recordAweme(MonitorBloggerMainRecordEvent event,long uid,Calendar calendar){
        Calendar beforeCalendar = ObjectUtil.cloneByStream(calendar);
        beforeCalendar.add(Calendar.HOUR_OF_DAY,-1);

        List<Aweme> awemes = awemeService.get24HourBloggerAwemes(uid);
        awemes.parallelStream().forEach (aweme -> {

            val awemeRecordOptional = tAwemeRecordRepository.findByAwemeIdAndRecordDate(aweme.getOAwemeId(), calendar.getTimeInMillis() / 1000);
            TAwemeRecord tAwemeRecord;

            if(awemeRecordOptional.isPresent()){
                tAwemeRecord = awemeRecordOptional.get();
            }else{

                tAwemeRecord = new TAwemeRecord();
                tAwemeRecord.setCreateBy(event.getSource());
                tAwemeRecord.setRecordDate(calendar.getTimeInMillis()/1000);
            }
            tAwemeRecord.setAwemeCreateTime(aweme.getOCreateTime());
            tAwemeRecord.setAwemeId(aweme.getOAwemeId());
            tAwemeRecord.setCycle(0);
            tAwemeRecord.setLikeCount(aweme.getODiggCount());
            tAwemeRecord.setLikeGrowth(0l);
            tAwemeRecord.setReviewCount((long)aweme.getOCommentCount());
            tAwemeRecord.setReviewGrowth(0l);
            tAwemeRecord.setViewCount(aweme.getOPlayCount());
            tAwemeRecord.setViewGrowth(0l);
            tAwemeRecord.setShareCount((long)aweme.getOShareCount());
            tAwemeRecord.setShareGrowth(0l);
            tAwemeRecord.setUid(aweme.getOUid());
            tAwemeRecord.setUpdateBy(event.getSource());

            Optional<TAwemeRecord> tAwemeRecordOptional = tAwemeRecordRepository.findByAwemeIdAndRecordDate(tAwemeRecord.getAwemeId(),beforeCalendar.getTimeInMillis()/1000);

            if(tAwemeRecordOptional.isPresent()){
                TAwemeRecord beforeTAwemeRecord = tAwemeRecordOptional.get();
                tAwemeRecord.setLikeGrowth(tAwemeRecord.getLikeCount() - beforeTAwemeRecord.getLikeCount());
                tAwemeRecord.setReviewGrowth(tAwemeRecord.getReviewCount() - beforeTAwemeRecord.getReviewCount());
                tAwemeRecord.setViewGrowth(tAwemeRecord.getViewCount() - beforeTAwemeRecord.getViewCount());
                tAwemeRecord.setShareGrowth(tAwemeRecord.getShareCount() - beforeTAwemeRecord.getShareCount());
            }
            tAwemeRecordRepository.save(tAwemeRecord);

        });
    }

    public static class MonitorBloggerMainRecordEvent extends Event {

        public MonitorBloggerMainRecordEvent(List<SlimBloggerDto> slimBloggers) {
            super("MonitorBloggerMainRecord");
            this.slimBloggers = slimBloggers;
        }
        public MonitorBloggerMainRecordEvent(Event event, List<SlimBloggerDto> slimBloggers) {
            super(event,"MonitorBloggerMainRecord");
            this.slimBloggers = slimBloggers;
        }
        private List<SlimBloggerDto> slimBloggers;

    }
}
